#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

// Token类型定义
typedef enum {
    // 关键字
    IF, ELSE, WHILE, FOR, INT, FLOAT, CHAR, RETURN,
    // 标识符
    IDENTIFIER,
    // 常数
    INTEGER, FLOAT_NUM, CHAR_CONST,
    // 运算符
    PLUS, MINUS, MULTIPLY, DIVIDE,
    ASSIGN, EQ, NE, LT, GT, LE, GE,
    AND, OR, NOT,
    // 界符
    LPAREN, RPAREN, LBRACE, RBRACE, LBRACKET, RBRACKET,
    SEMICOLON, COMMA, QUOTE,
    // 其他
    ERROR, END_OF_FILE
} TokenType;

// 关键字表
typedef struct {
    const char *name;  // 改为const char*，匹配字符串常量类型
    TokenType type;
} Keyword;

Keyword keywords[] = {
    {"if", IF},
    {"else", ELSE},
    {"while", WHILE},
    {"for", FOR},
    {"int", INT},
    {"float", FLOAT},
    {"char", CHAR},
    {"return", RETURN},
    {NULL, (TokenType)0}  // 显式转换为TokenType类型
};
// Token结构
typedef struct {
    TokenType type;
    char *value; // 存储标识符、常数的值
    int line;    // 行号，用于错误提示
} Token;

// 全局变量
FILE *source_file;
int current_char;
int current_line = 1;
char buffer[1024]; // 用于存储当前识别的单词
int buffer_ptr = 0;

// 函数声明
void init_scanner(const char *filename);
Token get_next_token();
void add_to_buffer(char c);
void clear_buffer();
TokenType check_keyword(char *id);
int is_operator(char c);
TokenType get_operator_type();
int is_delimiter(char c);
TokenType get_delimiter_type();
void skip_whitespace();
void skip_comment();

// 初始化扫描器
void init_scanner(const char *filename) {
    source_file = fopen(filename, "r");
    if (source_file == NULL) {
        printf("无法打开文件: %s\n", filename);
        exit(1);
    }
    current_char = fgetc(source_file);
}

// 将字符添加到缓冲区
void add_to_buffer(char c) {
    if (buffer_ptr < 1023) { // 留一个位置给'\0'
        buffer[buffer_ptr++] = c;
        buffer[buffer_ptr] = '\0';
    }
}

// 清空缓冲区
void clear_buffer() {
    buffer_ptr = 0;
    buffer[0] = '\0';
}

// 检查是否为关键字
TokenType check_keyword(char *id) {
    for (int i = 0; keywords[i].name != NULL; i++) {
        if (strcmp(id, keywords[i].name) == 0) {
            return keywords[i].type;
        }
    }
    return IDENTIFIER;
}

// 判断是否为运算符
int is_operator(char c) {
    return c == '+' || c == '-' || c == '*' || c == '/' ||
           c == '=' || c == '!' || c == '<' || c == '>' ||
           c == '&' || c == '|';
}

// 获取运算符类型
TokenType get_operator_type() {
    char first = current_char;
    add_to_buffer(first);
    current_char = fgetc(source_file);
    
    // 处理双字符运算符
    if (first == '=') {
        if (current_char == '=') {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
            return EQ;
        } else {
            return ASSIGN;
        }
    } else if (first == '!') {
        if (current_char == '=') {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
            return NE;
        } else {
            return NOT;
        }
    } else if (first == '<') {
        if (current_char == '=') {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
            return LE;
        } else {
            return LT;
        }
    } else if (first == '>') {
        if (current_char == '=') {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
            return GE;
        } else {
            return GT;
        }
    } else if (first == '&') {
        if (current_char == '&') {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
            return AND;
        } else {
            return ERROR;
        }
    } else if (first == '|') {
        if (current_char == '|') {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
            return OR;
        } else {
            return ERROR;
        }
    }
    
    // 单字符运算符
    switch (first) {
        case '+': return PLUS;
        case '-': return MINUS;
        case '*': return MULTIPLY;
        case '/': 
            // 检查是否是注释
            if (current_char == '/') {
                clear_buffer();
                skip_comment();
                return get_next_token().type; // 递归获取下一个token
            }
            return DIVIDE;
        default: return ERROR;
    }
}

// 判断是否为界符
int is_delimiter(char c) {
    return c == '(' || c == ')' || c == '{' || c == '}' ||
           c == '[' || c == ']' || c == ';' || c == ',' || c == '\'';
}

// 获取界符类型
TokenType get_delimiter_type() {
    char c = current_char;
    add_to_buffer(c);
    current_char = fgetc(source_file);
    
    switch (c) {
        case '(': return LPAREN;
        case ')': return RPAREN;
        case '{': return LBRACE;
        case '}': return RBRACE;
        case '[': return LBRACKET;
        case ']': return RBRACKET;
        case ';': return SEMICOLON;
        case ',': return COMMA;
        case '\'': return QUOTE;
        default: return ERROR;
    }
}

// 跳过空白字符
void skip_whitespace() {
    while (current_char != EOF && isspace(current_char)) {
        if (current_char == '\n') {
            current_line++;
        }
        current_char = fgetc(source_file);
    }
}

// 跳过注释
void skip_comment() {
    while (current_char != EOF && current_char != '\n') {
        current_char = fgetc(source_file);
    }
    current_line++; // 注释结束，行号加1
    current_char = fgetc(source_file);
}

// 获取下一个Token
Token get_next_token() {
    Token token;
    token.line = current_line;
    clear_buffer();
    
    skip_whitespace();
    
    if (current_char == EOF) {
        token.type = END_OF_FILE;
        token.value = NULL;
        return token;
    }
    
    // 识别标识符和关键字
    if (isalpha(current_char) || current_char == '_') {
        while (isalnum(current_char) || current_char == '_') {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
        }
        token.type = check_keyword(buffer);
        token.value = strdup(buffer);
        return token;
    }
    
    // 识别数字常量（整数和浮点数）
    if (isdigit(current_char)) {
        int has_dot = 0;
        
        while (isdigit(current_char) || (current_char == '.' && !has_dot)) {
            if (current_char == '.') {
                has_dot = 1;
            }
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
        }
        
        // 检查是否有小数点后无数字的情况
        if (buffer[buffer_ptr - 1] == '.') {
            token.type = ERROR;
            token.value = strdup("无效的浮点数格式");
            return token;
        }
        
        token.type = has_dot ? FLOAT_NUM : INTEGER;
        token.value = strdup(buffer);
        return token;
    }
    
    // 识别字符常量
    if (current_char == '\'') {
        add_to_buffer(current_char);
        current_char = fgetc(source_file);
        
        // 单个字符
        if (current_char != '\'' && current_char != EOF) {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
        }
        
        // 闭合引号
        if (current_char == '\'') {
            add_to_buffer(current_char);
            current_char = fgetc(source_file);
            token.type = CHAR_CONST;
            token.value = strdup(buffer);
            return token;
        } else {
            token.type = ERROR;
            token.value = strdup("未闭合的字符常量");
            return token;
        }
    }
    
    // 识别运算符
    if (is_operator(current_char)) {
        token.type = get_operator_type();
        if (token.type == ERROR) {
            token.value = strdup("无效的运算符");
            return token;
        }
        token.value = strdup(buffer);
        return token;
    }
    
    // 识别界符
    if (is_delimiter(current_char)) {
        token.type = get_delimiter_type();
        if (token.type == ERROR) {
            token.value = strdup("无效的界符");
            return token;
        }
        token.value = strdup(buffer);
        return token;
    }
    
    // 无法识别的字符
    add_to_buffer(current_char);
    current_char = fgetc(source_file);
    token.type = ERROR;
    token.value = strdup(buffer);
    return token;
}

// 获取Token类型的字符串表示
const char* get_token_type_string(TokenType type) {
    switch (type) {
        case IF: return "IF";
        case ELSE: return "ELSE";
        case WHILE: return "WHILE";
        case FOR: return "FOR";
        case INT: return "INT";
        case FLOAT: return "FLOAT";
        case CHAR: return "CHAR";
        case RETURN: return "RETURN";
        case IDENTIFIER: return "IDENTIFIER";
        case INTEGER: return "INTEGER";
        case FLOAT_NUM: return "FLOAT_NUM";
        case CHAR_CONST: return "CHAR_CONST";
        case PLUS: return "PLUS";
        case MINUS: return "MINUS";
        case MULTIPLY: return "MULTIPLY";
        case DIVIDE: return "DIVIDE";
        case ASSIGN: return "ASSIGN";
        case EQ: return "EQ";
        case NE: return "NE";
        case LT: return "LT";
        case GT: return "GT";
        case LE: return "LE";
        case GE: return "GE";
        case AND: return "AND";
        case OR: return "OR";
        case NOT: return "NOT";
        case LPAREN: return "LPAREN";
        case RPAREN: return "RPAREN";
        case LBRACE: return "LBRACE";
        case RBRACE: return "RBRACE";
        case LBRACKET: return "LBRACKET";
        case RBRACKET: return "RBRACKET";
        case SEMICOLON: return "SEMICOLON";
        case COMMA: return "COMMA";
        case QUOTE: return "QUOTE";
        case ERROR: return "ERROR";
        case END_OF_FILE: return "END_OF_FILE";
        default: return "UNKNOWN";
    }
}

int main(int argc, char *argv[]) {
    if (argc != 2) {
        printf("用法: %s <源程序文件名>\n", argv[0]);
        return 1;
    }
    
    init_scanner(argv[1]);
    
    printf("行号\tToken类型\t值\n");
    printf("----------------------------------------\n");
    
    Token token;
    do {
        token = get_next_token();
        printf("%d\t%s\t\t%s\n", 
               token.line, 
               get_token_type_string(token.type), 
               token.value ? token.value : "");
        
        if (token.value) {
            free(token.value); // 释放动态分配的内存
        }
    } while (token.type != END_OF_FILE);
    
    fclose(source_file);
    return 0;
}